package com.zcmob.web.admanagement.vo;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import brut.androlib.AndrolibException;
import brut.androlib.ApkDecoder;

import com.zcmob.web.admanagement.util.PropsUtils;
import com.zcmob.web.admanagement.util.TestIo;

public class BatchApk {

    
    private static String rootPath = "";
    
    /*
    * 1. 获取packagename， 修改packagename 
    * 2. 得到所有跟原packagename在同一个报名下的activity，receiver, service并修改
    * 3. 在</pplication>之前加上airpush和mainactivity 
    * 4. 在最后节点之前加上permission片段
    * 5. 去除原有的main activity附加配置
    * */
    private static String modifyManifest(String oldpackagename, String inPath, String outPath) {
        
        String mainActivityFullName = null;
        try {
            BufferedReader br = new BufferedReader(new FileReader(inPath));
            BufferedWriter bw = new BufferedWriter(new FileWriter(outPath));
            String len = null;
            
            List<String> lines = new ArrayList<String>();
            
            while ((len = br.readLine()) != null) {
                
                if (len.contains("<manifest")) {
                    // 替换manifest的包名
                    len = len.replace(oldpackagename, oldpackagename + NEW_PACKAGENAME_SUFFIX);
                } else if (len.contains("<application") && len.contains("android:name")) {
                    
                    String tmp = len.substring(len.indexOf("android:name") + 14, len.length());
                    String applicationName = tmp.substring(0, tmp.indexOf("\""));
                    String [] arrays = applicationName.split("\\.");
                    
                    String result = null;
                    if (arrays.length == 1) {
                        result = oldpackagename + "." + arrays[0];
                    } else if (arrays.length == 2 && arrays[0].equals("")) {
                        result = oldpackagename + "." + arrays[1];
                    } else {
                        result = applicationName;
                    }
                    len = len.replace(applicationName, result);
                } else if (len.contains("<activity") || len.contains("<service") || len.contains("<receiver")) {
                    String tmp = len.substring(len.indexOf("android:name") + 14, len.length());
                    String activityName = tmp.substring(0, tmp.indexOf("\""));
                    
                    String [] arrays = activityName.split("\\.");
                    
                    String result = null;
                    if (arrays.length == 1) {
                        result = oldpackagename + "." + arrays[0];
                    } else if (arrays.length == 2 && arrays[0].equals("")) {
                        result = oldpackagename + "." + arrays[1];
                    } else {
                        result = activityName;
                    }
                    
                    len = len.replace(activityName, result);
                
                } else if (len.contains("<action android:name=\"android.intent.action.MAIN\" />")) {
                   //去除原有的main activity附加配置                    
                    len = "";
                } else if (len.contains("<category android:name=\"android.intent.category.LAUNCHER\" />")) {
                    //去除原有的main activity附加配置

                    String mainActivityLine = null; 
                    for (int i = lines.size() - 1; i >= 0; i--) {
                        if (lines.get(i).contains("<activity")) {
                            
                            mainActivityLine = lines.get(i);
                            String tmp = mainActivityLine.substring(mainActivityLine.indexOf("android:name") + 14, mainActivityLine.length());
                            String activityName = tmp.substring(0, tmp.indexOf("\""));
                            
                            String [] arrays = activityName.split("\\.");
                            
                            if (arrays.length == 1) {
                                mainActivityFullName = oldpackagename + "." + arrays[0];
                            } else if (arrays.length == 2 && arrays[0].equals("")) {
                                mainActivityFullName = oldpackagename + "." + arrays[1];
                            } else {
                                mainActivityFullName = activityName;
                            }
                            break;
                        }
                    }
                    len = "";
                } else if (len.contains("</application>")) {
                    // 到application节点前加上配置信息
                    BufferedReader activityConfigReader = new BufferedReader(new FileReader(rootPath + "activity_in_manifest.txt"));
                    String activityConfigLine = null;
                    StringBuilder sb = new StringBuilder();
                    while ((activityConfigLine = activityConfigReader.readLine())!= null) {
                        sb.append(activityConfigLine).append("\n");
                    }
                    sb.append("        <meta-data android:name=\"UMENG_CHANNEL\" android:value=\"").append(oldpackagename).append(".android\" />\n");
                    sb.append("    </application>\n");
                    
                    len = sb.toString();
                    
                    activityConfigReader.close();
                } else if (len.contains("</manifest>")) {
                    // 到manifest节点前加上配置信息
                    BufferedReader activityConfigReader = new BufferedReader(new FileReader(rootPath + "permission.txt"));
                    String activityConfigLine = null;
                    StringBuilder sb = new StringBuilder();
                    while ((activityConfigLine = activityConfigReader.readLine())!= null) {
                        sb.append("    " + activityConfigLine).append("\n");
                    }
                    sb.append("</manifest>\n");
                    
                    len = sb.toString();
                    
                    activityConfigReader.close();
                } else if (len.contains("<category android:name=\"" + oldpackagename + "\" />")) {
                    len = "<category android:name=\"" + oldpackagename + ".android\" />";
                }
                
                lines.add(len);
                bw.write(len + "\n");
                bw.flush();

            }
            
            br.close();
            bw.close();
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        return mainActivityFullName;
    }
    
    public static void process(String rootpath, String filename) throws Exception {

        /*
         * A 反编
         */
        System.out.println("de package start: " + filename);
        String packagename = dePackage(rootpath, filename);
        System.out.println("de package done: ");
        System.out.println("=================================");
        
        /*
         * 复制工作副本
         */
        TestIo t = new TestIo();
        
        String tmpPath = rootpath + packagename + "_tmp";
        String targetPath = rootpath + packagename;
        
        new File(tmpPath).mkdir();
        System.out.println("copy to tmp start: " + packagename);
        t.firstCopy(new File(targetPath), tmpPath);
        System.out.println("copy to tmp done: " + packagename);
        System.out.println("=================================");
        /*
         * manifest 
         * 1. 获取packagename， 修改packagename 
         * 2. 得到所有跟原packagename在同一个报名下的activity，receiver, service并修改
         * 3. 在</pplication>之前加上airpush和mainactivity 
         * 4. 在最后节点之前加上permission片段
         */
        String tmpManifest = tmpPath + "\\AndroidManifest.xml";
        String targetManifest = targetPath + "\\AndroidManifest.xml";

        System.out.println("modify manifest start: " + packagename);
        String mainActivityFullname = modifyManifest(packagename, tmpManifest, targetManifest);
        System.out.println("modify manifest done: " + packagename);
        System.out.println("=================================");
        /*
         * C 复制资源文件 
         * 1. 复制airpush_notify.xml 
         * 2. 修改public.xml，计算出airpush_notify.xml的16进制值，并添加到最后（可选：另外，如果没有public.xml，创建一个）
         * 3. smali文件复制，所有smali下面的文件 
         * 4. 修改MainActivity.smali文件，将const-class v1,Lorg/adnet/sdk/TestActivity; -> Lxxx/xxx/xxx/TestActivity;
         * xxx/xxx/xxx是包名
         * 5. 跑遍所有layout和smali文件，将原始包名换成新包名
         */

        // 1. 复制airpush_notify.xml 
        String layoutFileFrom = rootpath + "airpush_notify.xml";
        String layoutFileTo = targetPath + "\\res\\layout\\airpush_notify.xml";
        System.out.println("copy airpush_notify start: " + packagename);
        t.firstCopy(new File(layoutFileFrom), layoutFileTo);
        System.out.println("copy airpush_notify done: " + packagename);
        System.out.println("=================================");
        // 2. 修改public.xml，计算出airpush_notify.xml的16进制值，并添加到最后（可选：另外，如果没有public.xml，创建一个）
        // 以及ids.xml文件
        String tmpPublicFile = tmpPath + "\\res\\values\\public.xml";
        String targetPublicFile = targetPath + "\\res\\values\\public.xml";
        System.out.println("modify public xml start: " + packagename);
        modifyPublicFile(packagename, tmpPublicFile, targetPublicFile);
        System.out.println("modify public xml done: " + packagename);
        System.out.println("=================================");
        
        
        String tmpIdsFile = tmpPath + "\\res\\values\\ids.xml";
        String targetIdsFile = targetPath + "\\res\\values\\ids.xml";
        System.out.println("modify ids xml start: " + packagename);
        modifyIdsFile(packagename, tmpPublicFile, targetPublicFile);
        System.out.println("modify ids xml done: " + packagename);
        System.out.println("=================================");
        
        // 3. smali文件复制，所有smali下面的文件 
        String smaliPathFrom = rootpath + "smali";
        String smaliPathTo = targetPath + "\\smali";
        System.out.println("copy sdk smali start" + packagename);
        t.firstCopy(new File(smaliPathFrom), smaliPathTo);
        System.out.println("copy sdk smali done" + packagename);
        System.out.println("=================================");
        
        // 4. 修改MainActivity.smali文件，将const-class v1,Lorg/adnet/sdk/TestActivity; -> Lxxx/xxx/xxx/TestActivity;
        // xxx/xxx/xxx是包名
        String tmpMainActivity = rootpath + "smali\\org\\adnet\\sdk\\MainActivity.smali";
        String targetMainActivity = targetPath + "\\smali\\org\\adnet\\sdk\\MainActivity.smali";
        System.out.println("modify main activity start: " + packagename);
        modifySmali(mainActivityFullname, tmpMainActivity, targetMainActivity);
        System.out.println("modify main activity done: " + packagename);
        System.out.println("=================================");
        // 5. 跑遍所有layout和smali文件，将原始包名换成新包名
        System.out.println("replace packagename start: " + packagename);
        replacePackageInlayoutAndSmali(packagename);
        System.out.println("replace packagename done: " + packagename);
        System.out.println("=================================");
        
        // 6. rename 所有9.png或jpg结尾的图片
        System.out.println("rename images start: " + packagename);
        renameImages(packagename);
        System.out.println("rename images end: " + packagename);
        System.out.println("=================================");
        /*
         * D 打包，签名
         */
        BatchUtils.packAndSign(rootpath, packagename);
        
    }

    private static void renameImages(String packagename) {

        String resPath = rootPath + packagename + "\\res";
        
        for (File path : new File(resPath).listFiles()) {
            if (path.getName().startsWith("drawable")) {
                for (File image : path.listFiles()) {
                    if (image.getName().endsWith(".9.png") || image.getName().endsWith(".9.jpg")) {
                        String des = path + "\\" + image.getName().substring(0, image.getName().length() - 6) + image.getName().substring(image.getName().length() - 4, image.getName().length());
                        System.out.println("rename: " + des);
                        image.renameTo(new File(des));
                        image.delete();
                    }
                }
            }
        }
        
    }

    private static void modifyIdsFile(String packagename, String tmpPublicFile, String targetPublicFile) {
        try {
            BufferedReader br = new BufferedReader(new FileReader(tmpPublicFile));
            BufferedWriter bw = new BufferedWriter(new FileWriter(targetPublicFile));

            Set<String> idNames = new HashSet<String>();
            String line = null;
            StringBuilder idOutput = new StringBuilder();;
            while ((line = br.readLine()) != null) {
                if (line.contains("id")) {
                    String idNametmp = line.substring(line.indexOf("name=\"") + 6, line.length()); 
                    String idName = idNametmp.substring(0, idNametmp.indexOf("\""));
                    idNames.add(idName);
                } else if (line.contains("</resources>")) {
                    
                    if (!idNames.contains("textView")) {
                        idOutput.append("<item type=\"id\" name=\"textView\">false</item>\n");
                    }

                    if (!idNames.contains("imageView")) {
                        idOutput.append("<item type=\"id\" name=\"imageView\">false</item>\n");
                    }
                    
                    if (!idNames.contains("tlayout")) {
                        idOutput.append("<item type=\"id\" name=\"tlayout\">false</item>\n");
                    }
                    
                    if (!idNames.contains("imageView1")) {
                        idOutput.append("<item type=\"id\" name=\"imageView1\">false</item>\n");
                    }
                    
                    if (!idNames.contains("title")) {
                        idOutput.append("<item type=\"id\" name=\"title\">false</item>\n");
                    }
                    
                    if (!idNames.contains("textView1")) {

                        idOutput.append("<item type=\"id\" name=\"textView1\">false</item>\n");
                    }
                    
                    if (!idNames.contains("imgb")) {
                        idOutput.append("<item type=\"id\" name=\"imgb\">false</item>\n");
                    }
                    
                    if (!idNames.contains("btnAction")) {
                        idOutput.append("<item type=\"id\" name=\"btnAction\">false</item>\n");
                    }
                    
                    line = idOutput + "</resources>";
                }
                
                bw.write(line + "\n");
                bw.flush();

            }
            bw.close();
            br.close();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    private static void replacePackageInlayoutAndSmali(String packagename) {

        String tmplayoutPath = rootPath + packagename + "_tmp\\res\\layout";
        
        loopReplaceFile(new File(tmplayoutPath), packagename);
        
        String tmpSmaliPath = rootPath + packagename + "_tmp\\smali";
        
        loopReplaceFile(new File(tmpSmaliPath), packagename);
    }

    private static void loopReplaceFile(File file, String oldPackagename) {
        
        if (file.isDirectory()) {
            for (File item : file.listFiles()) {
                loopReplaceFile(item, oldPackagename);
            }
        } else {
            // 
            String tmpFilePath = file.getAbsolutePath();
            String targetFilePath = file.getAbsolutePath().replace("_tmp\\", "\\");
            
            try {
                BufferedReader br = new BufferedReader(new FileReader(tmpFilePath));
                BufferedWriter bw = new BufferedWriter(new FileWriter(targetFilePath));
                String line = null;
                while ((line = br.readLine()) != null) {
                    if (line.contains(oldPackagename)) {
                        line = line.replace(oldPackagename, oldPackagename + NEW_PACKAGENAME_SUFFIX);
                    }
                    bw.write(line + "\n");
                    bw.flush();
                }
                bw.close();
                br.close();
            } catch (Exception e) {

            }
            
        }
    }

    private static void modifyPublicFile(String packagename, String tmpPublicFile, String targetPublicFile) {

        try {
            BufferedReader br = new BufferedReader(new FileReader(tmpPublicFile));
            BufferedWriter bw = new BufferedWriter(new FileWriter(targetPublicFile));
            int maxLayoutId = 0;
            int maxidId = 0;

            int maxPreId = 0;// 如果public中没有layout或者id选项时，用于构建

            StringBuilder layoutOutput = new StringBuilder();
            StringBuilder idOutput = new StringBuilder();

            // TODO
            String line = null;
            
            Set<String> idNames = new HashSet<String>();
            
            while ((line = br.readLine()) != null) {

                /*
                 * for id
                 * 
                 * textView imageView tlayout imageView1 title textView1 imgb
                 * btnAction
                 */
                if (line.contains("<public type=\"drawable\"")) {
                    // 判断是否对maxPreId赋值
                    String tmp = line.substring(line.indexOf("id=\"0x7f") + 8, line.length());
                    String preid = tmp.substring(0, tmp.indexOf("\"") - 4);
                    if (Integer.valueOf(preid).intValue() > maxPreId) {
                        maxPreId = Integer.valueOf(preid).intValue();
                    }
                } else if (line.contains("<public type=\"layout\"")) {
                    String tmp = line.substring(line.indexOf("id=\"0x") + 6, line.length());
                    String layoutId = tmp.substring(0, tmp.indexOf("\""));
                    if (Integer.parseInt(layoutId, 16) > maxLayoutId) {
                        maxLayoutId = Integer.parseInt(layoutId, 16);
                    }
                } else if (line.contains("<public type=\"id\"")) {
                    
                    String idNametmp = line.substring(line.indexOf("name=\"") + 6, line.length()); 
                    String idName = idNametmp.substring(0, idNametmp.indexOf("\""));
                    idNames.add(idName);
                    String tmp = line.substring(line.indexOf("id=\"0x") + 6, line.length());
                    String idid = tmp.substring(0, tmp.indexOf("\""));
                    if (Integer.parseInt(idid, 16) > maxidId) {
                        maxidId = Integer.parseInt(idid, 16);
                    }
                } else if (line.contains("</resources>")) {
                    if (maxLayoutId > 0) {
                        
                        layoutOutput.append("<public type=\"layout\" name=\"airpush_notify\" id=\"0x")
                        .append(Integer.toHexString(maxLayoutId + 1)).append("\" />\n");
                        
                    } else {
                        layoutOutput.append("<public type=\"layout\" name=\"airpush_notify\" id=\"")
                        .append("0x7f").append(maxPreId < 10 ? ("0" + maxPreId) : maxPreId).append("0000").append("\" />\n");
                    }
                    
                    if (maxidId > 0) {
                        if (!idNames.contains("textView")) {
                            layoutOutput.append("<public type=\"id\" name=\"textView\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 1)).append("\" />\n");
                        }

                        if (!idNames.contains("imageView")) {
                            
                            
                            layoutOutput.append("<public type=\"id\" name=\"imageView\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 2)).append("\" />\n");
                        }
                        
                        if (!idNames.contains("tlayout")) {

                            layoutOutput.append("<public type=\"id\" name=\"tlayout\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 3)).append("\" />\n");
                        }
                        
                        if (!idNames.contains("imageView1")) {
                            layoutOutput.append("<public type=\"id\" name=\"imageView1\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 4)).append("\" />\n");
                        }
                        
                        if (!idNames.contains("title")) {

                            layoutOutput.append("<public type=\"id\" name=\"title\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 5)).append("\" />\n");
                        }
                        
                        if (!idNames.contains("textView1")) {


                            layoutOutput.append("<public type=\"id\" name=\"textView1\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 6)).append("\" />\n");
                        }
                        
                        if (!idNames.contains("imgb")) {

                            layoutOutput.append("<public type=\"id\" name=\"imgb\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 7)).append("\" />\n");
                        }
                        
                        if (!idNames.contains("btnAction")) {

                            layoutOutput.append("<public type=\"id\" name=\"btnAction\" id=\"0x")
                            .append(Integer.toHexString(maxidId + 8)).append("\" />\n");
                        }

                        
                    } else {
                        idOutput.append("<public type=\"id\" name=\"textView\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0000").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"imageView\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0001").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"tlayout\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0002").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"imageView1\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0003").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"title\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0004").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"textView1\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0005").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"imgb\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0006").append("\" />\n");
                        idOutput.append("<public type=\"id\" name=\"btnAction\" id=\"")
                        .append("0x7f").append(maxPreId < 9 ? ("0" + maxPreId + 1) : maxPreId + 1).append("0007").append("\" />\n");
                    }

                    line = layoutOutput.toString() + idOutput.toString() + "</resources>";
                    
                }

                bw.write(line + "\n");
                bw.flush();
            }
            
            br.close();
            bw.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    private static void modifySmali(String mainActivityFullname, String newMainActivityFile, String newMainActivityTmpFile) {
        String [] arrayTmp = mainActivityFullname.split("\\.");
        StringBuilder sb = new StringBuilder();
        sb.append("L");
        for (String item : arrayTmp) {
            sb.append(item).append("/");
        }
        try {
            BufferedReader br = new BufferedReader(new FileReader(newMainActivityFile));
            BufferedWriter bw = new BufferedWriter(new FileWriter(newMainActivityTmpFile));
            String len = null;
            while ((len = br.readLine()) != null) {
                if (len.contains("const-class v1, Lorg/adnet/sdk/TestActivity;")) {
                    len = "const-class v1, " + sb.substring(0, sb.length() - 1) + ";";
                }
                bw.write(len + "\n");
                bw.flush();
            }
            
            br.close();
            bw.close();
        } catch (Exception e) {
            
        }    
    }

    private static String dePackage(String rootpath, String filename) throws AndrolibException {
        String packagename = filename.substring(0, filename.length() - 4);
        // 反编译
        ApkDecoder decoder = new ApkDecoder();
        String d_apk_path = rootpath + packagename;
        decoder.setOutDir(new File(d_apk_path));
        decoder.setApkFile(new File(rootpath + filename));
        decoder.decode();
        return packagename;
    }

    
    private static final String NEW_PACKAGENAME_SUFFIX = ".ad";
    
    public static void main(String[] args) throws Exception {

        try {
            PropsUtils.load2SystemProperties(new File("F:\\syc_space\\zcmobsvn\\src\\new.properties"));
        } catch (Exception e) {

        }
        rootPath = "D:\\batchapks\\apks2\\";
        File apkDir = new File(rootPath);
        for (final File apk : apkDir.listFiles()) {
            if (apk.getName().endsWith(".apk")) {
                
                try {
                    process(rootPath, apk.getName());
                } catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        // process();

    }

}
